
package com.airplane.app.appwidget;

/*
 * Copyright (C) 2009 China Mobile Research Institute
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.airplane.app.R;
import com.airplane.app.utils.MyLogger;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.widget.RemoteViews;

public class ModeWidget extends AppWidgetProvider {
    private static MyLogger logger = MyLogger.getLogger("ModeWidget");
    static final ComponentName THIS_APPWIDGET = new ComponentName("com.airplane.app",
            "com.airplane.app.appwidget");

    private static final int BUTTON_WIFI = 0;
    private static final int BUTTON_BRIGHTNESS = 1;
    private static final int BUTTON_SYNC = 2;
    private static final int BUTTON_GPS = 3;
    private static final int BUTTON_BLUETOOTH = 4;

    // This widget keeps track of two sets of states:
    // "3-state": STATE_DISABLED, STATE_ENABLED, STATE_INTERMEDIATE
    // "5-state": STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON, STATE_TURNING_OFF, STATE_UNKNOWN
    private static final int STATE_DISABLED = 0;
    private static final int STATE_ENABLED = 1;
    private static final int STATE_TURNING_ON = 2;
    private static final int STATE_TURNING_OFF = 3;
    private static final int STATE_UNKNOWN = 4;
    private static final int STATE_INTERMEDIATE = 5;

    private static final int POWEROFF_DATAONBOOT = 0;/**
     * This is for DataConnectionWidgetProvider to store the state when changing the airplane toggle.
     *    if 0 ,it is STATE_DISABLED; if 1 ,it is STATE_ENABLED.
     */
    public static final String DATA_CONNECTION_STATE_BEFORE_AIRPLANE = "data_connection_state";
    private static boolean IS_STATE_ENABLED_BEFORE_AIRPLANE=false;

    private static final StateTracker sWifiState = new WifiStateTracker();
    private static final StateTracker sBluetoothState = null;

    private static boolean wififlag = false;
    private static boolean wapiflag = false;
    private static boolean tempState;
    private static boolean dataswitching = false;

    private static int mBrightness;

    /**
     * The state machine for Wifi and Bluetooth toggling, tracking
     * reality versus the user's intent.
     *
     * This is necessary because reality moves relatively slowly
     * (turning on &amp; off radio drivers), compared to user's
     * expectations.
     */
    private abstract static class StateTracker {
        // Is the state in the process of changing?
        private boolean mInTransition = false;
        private Boolean mActualState = null;  // initially not set
        private Boolean mIntendedState = null;  // initially not set

        // Did a toggle request arrive while a state update was
        // already in-flight?  If so, the mIntendedState needs to be
        // requested when the other one is done, unless we happened to
        // arrive at that state already.
        private boolean mDeferredStateChangeRequestNeeded = false;

        /**
         * User pressed a button to change the state.  Something
         * should immediately appear to the user afterwards, even if
         * we effectively do nothing.  Their press must be heard.
         */
        public final void toggleState(Context context) {
            int currentState = getTriState(context);
            boolean newState = false;
            switch (currentState) {
                case STATE_ENABLED:
                    newState = false;
                    break;
                case STATE_DISABLED:
                    newState = true;
                    break;
                case STATE_INTERMEDIATE:
                    if (mIntendedState != null) {
                        newState = !mIntendedState;
                    }
                    break;
            }
            mIntendedState = newState;
            if (mInTransition) {
                // We don't send off a transition request if we're
                // already transitioning.  Makes our state tracking
                // easier, and is probably nicer on lower levels.
                // (even though they should be able to take it...)
                mDeferredStateChangeRequestNeeded = true;
            } else {
                mInTransition = true;
                requestStateChange(context, newState);
            }
        }

        /**
         * Update internal state from a broadcast state change.
         */
        public abstract void onActualStateChange(Context context, Intent intent);

        /**
         * Sets the value that we're now in.  To be called from onActualStateChange.
         *
         * @param newState one of STATE_DISABLED, STATE_ENABLED, STATE_TURNING_ON,
         *                 STATE_TURNING_OFF, STATE_UNKNOWN
         */
        protected final void setCurrentState(Context context, int newState) {
            final boolean wasInTransition = mInTransition;
            switch (newState) {
                case STATE_DISABLED:
                    mInTransition = false;
                    mActualState = false;
                    break;
                case STATE_ENABLED:
                    mInTransition = false;
                    mActualState = true;
                    break;
                case STATE_TURNING_ON:
                    mInTransition = true;
                    mActualState = false;
                    break;
                case STATE_TURNING_OFF:
                    mInTransition = true;
                    mActualState = true;
                    break;
            }

            if (wasInTransition && !mInTransition) {
                if (mDeferredStateChangeRequestNeeded) {
                    logger.d("processing deferred state change");
                    if (mActualState != null && mIntendedState != null
                            && mIntendedState.equals(mActualState)) {
                        logger.d("... but intended state matches, so no changes.");
                    } else if (mIntendedState != null) {
                        mInTransition = true;
                        requestStateChange(context, mIntendedState);
                    }
                    mDeferredStateChangeRequestNeeded = false;
                }
            }
        }


        /**
         * If we're in a transition mode, this returns true if we're
         * transitioning towards being enabled.
         */
        public final boolean isTurningOn() {
            return mIntendedState != null && mIntendedState;
        }

        /**
         * Returns simplified 3-state value from underlying 5-state.
         *
         * @param context
         * @return STATE_ENABLED, STATE_DISABLED, or STATE_INTERMEDIATE
         */
        public final int getTriState(Context context) {
            if (mInTransition) {
                // If we know we just got a toggle request recently
                // (which set mInTransition), don't even ask the
                // underlying interface for its state.  We know we're
                // changing.  This avoids blocking the UI thread
                // during UI refresh post-toggle if the underlying
                // service state accessor has coarse locking on its
                // state (to be fixed separately).
                return STATE_INTERMEDIATE;
            }
            switch (getActualState(context)) {
                case STATE_DISABLED:
                    return STATE_DISABLED;
                case STATE_ENABLED:
                    return STATE_ENABLED;
                default:
                    return STATE_INTERMEDIATE;
            }
        }

        /**
         * Gets underlying actual state.
         *
         * @param context
         * @return STATE_ENABLED, STATE_DISABLED, STATE_ENABLING, STATE_DISABLING,
         *         or or STATE_UNKNOWN.
         */
        public abstract int getActualState(Context context);

        /**
         * Actually make the desired change to the underlying radio
         * API.
         */
        protected abstract void requestStateChange(Context context, boolean desiredState);
    }

    /**
     * Subclass of StateTracker to get/set Wifi state.
     */
    private static final class WifiStateTracker extends StateTracker {
        @Override
        public int getActualState(Context context) {
            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            if (wifiManager != null) {
                return wifiStateToFiveState(wifiManager.getWifiState());
            }
            return STATE_UNKNOWN;
        }

        @Override
        protected void requestStateChange(Context context, final boolean desiredState) {
            final WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            if (wifiManager == null) {
                logger.d("No wifiManager.");
                return;
            }

            // Actually request the wifi change and persistent
            // settings write off the UI thread, as it can take a
            // user-noticeable amount of time, especially if there's
            // disk contention.
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... args) {
                    /**
                     * Disable tethering if enabling Wifi
                     *//*
                    int wifiApState = wifiManager.getWifiApState();
                    if (desiredState && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
                                         (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
                        wifiManager.setWifiApEnabled(null, false);
                    }

                    logger.d("SettingsAppWidgetProvider, will setWifiEnabled="+desiredState);
                    wifiManager.setWifiEnabled(desiredState);*/
                    return null;
                }
            }.execute();
        }

        @Override
        public void onActualStateChange(Context context, Intent intent) {
            if (!WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
                return;
            }
            int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
            setCurrentState(context, wifiStateToFiveState(wifiState));
        }

        /**
         * Converts WifiManager's state values into our
         * Wifi/Bluetooth-common state values.
         */
        private static int wifiStateToFiveState(int wifiState) {
            switch (wifiState) {
                case WifiManager.WIFI_STATE_DISABLED:
                    return STATE_DISABLED;
                case WifiManager.WIFI_STATE_ENABLED:
                    return STATE_ENABLED;
                case WifiManager.WIFI_STATE_DISABLING:
                    return STATE_TURNING_OFF;
                case WifiManager.WIFI_STATE_ENABLING:
                    return STATE_TURNING_ON;
                default:
                    return STATE_UNKNOWN;
            }
        }
    }

    private boolean isAirplaneMode(Context context) {
        return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) > 0;
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
        // Update each requested appWidgetId
        IS_STATE_ENABLED_BEFORE_AIRPLANE=Settings.System.getInt(context.getContentResolver(),
                DATA_CONNECTION_STATE_BEFORE_AIRPLANE, 0) != 0;
        RemoteViews view = buildUpdate(context, -1);

        for (int i = 0; i < appWidgetIds.length; i++) {
            appWidgetManager.updateAppWidget(appWidgetIds[i], view);
        }
    }


    @Override
    public void onEnabled(Context context) {/*
        PackageManager pm = context.getPackageManager();
        pm.setComponentEnabledSetting(
                new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);*/
    }

    @Override
    public void onDisabled(Context context) {/*
        Class clazz = com.android.settings.widget.SettingsAppWidgetProvider.class;
        PackageManager pm = context.getPackageManager();
        pm.setComponentEnabledSetting(
                new ComponentName("com.android.settings", ".widget.SettingsAppWidgetProvider"),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);*/
    }


    /**
     * Load image for given widget and build {@link RemoteViews} for it.
     */
    static RemoteViews buildUpdate(Context context, int appWidgetId) {
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
        views.setOnClickPendingIntent(R.id.btn_wifi, getLaunchPendingIntent(context, appWidgetId,
                BUTTON_WIFI));
        views.setOnClickPendingIntent(R.id.btn_brightness, getLaunchPendingIntent(context,
                appWidgetId, BUTTON_BRIGHTNESS));
        views.setOnClickPendingIntent(R.id.btn_sync, getLaunchPendingIntent(context, appWidgetId,
                BUTTON_SYNC));
        views.setOnClickPendingIntent(R.id.btn_gps, getLaunchPendingIntent(context, appWidgetId,
                BUTTON_GPS));
        views.setOnClickPendingIntent(R.id.btn_bluetooth, getLaunchPendingIntent(context,
                appWidgetId, BUTTON_BLUETOOTH));

        updateButtons(views, context);
        return views;
    }

    /**
     * Creates PendingIntent to notify the widget of a button click.
     *
     * @param context
     * @param appWidgetId
     * @return
     */
    private static PendingIntent getLaunchPendingIntent(Context context, int appWidgetId,
            int buttonId) {
        Intent launchIntent = new Intent();
        launchIntent.setClass(context, ModeWidget.class);
        launchIntent.addCategory(Intent.CATEGORY_ALTERNATIVE);
        launchIntent.setData(Uri.parse("custom:" + buttonId));
        PendingIntent pi = PendingIntent.getBroadcast(context, 0 /* no requestCode */,
                launchIntent, 0 /* no flags */);
        return pi;
    }

    /**
     * Updates the buttons based on the underlying states of wifi, etc.
     *
     * @param views   The RemoteViews to update.
     * @param context
     */
    private static void updateButtons(RemoteViews views, Context context) {

        switch (sWifiState.getTriState(context)) {
            case STATE_DISABLED:
                logger.d("Updating wifi button,state =  "+STATE_DISABLED);
                views.setImageViewResource(R.id.img_wifi, R.drawable.cmcc_setting_vifi_nor);
                views.setImageViewResource(R.id.ind_wifi, R.drawable.appwidget_settings_ind_off_l);
                break;
            case STATE_ENABLED:
                logger.d("Updating wifi button,state =  "+STATE_ENABLED);
                views.setImageViewResource(R.id.img_wifi, R.drawable.cmcc_setting_vifi_down);
                views.setImageViewResource(R.id.ind_wifi, R.drawable.appwidget_settings_ind_on_l);
                break;
            case STATE_INTERMEDIATE:
                // In the transitional state, the bottom green bar
                // shows the tri-state (on, off, transitioning), but
                // the top dark-gray-or-bright-white logo shows the
                // user's intent.  This is much easier to see in
                // sunlight.
                if (sWifiState.isTurningOn()) {
                    views.setImageViewResource(R.id.img_wifi, R.drawable.cmcc_setting_vifi_nor);
                    views.setImageViewResource(R.id.ind_wifi, R.drawable.appwidget_settings_ind_mid_l);
                } else {
                    views.setImageViewResource(R.id.img_wifi, R.drawable.cmcc_setting_vifi_nor);
                    views.setImageViewResource(R.id.ind_wifi, R.drawable.appwidget_settings_ind_mid_l);
                }
                break;
        }

//        if (getBrightnessMode(context)) {
//            //views.setImageViewResource(R.id.img_brightness, R.drawable.ic_appwidget_settings_brightness_auto);
//            views.setImageViewResource(R.id.ind_brightness, R.drawable.appwidget_settings_ind_on_r);
//        } else if (getBrightness(context)) {
//            if(mBrightness == MAXIMUM_BACKLIGHT) {
                views.setImageViewResource(R.id.img_brightness, R.drawable.cmcc_setting_brightness_hl);
//            } else {
//                views.setImageViewResource(R.id.img_brightness, R.drawable.cmcc_setting_brightness_down);
//            }
//            views.setImageViewResource(R.id.ind_brightness, R.drawable.appwidget_settings_ind_on_r);
//        } else {
//            views.setImageViewResource(R.id.img_brightness, R.drawable.cmcc_setting_brightness_nor);
//            views.setImageViewResource(R.id.ind_brightness, R.drawable.appwidget_settings_ind_off_r);
//        }

        switch(getDataOnBootState(context)){
            case STATE_DISABLED:
                views.setImageViewResource(R.id.img_sync, R.drawable.cmcc_setting_conversion_nor);
                views.setImageViewResource(R.id.ind_sync, R.drawable.appwidget_settings_ind_off_c);
                break;
            case STATE_ENABLED:
                views.setImageViewResource(R.id.img_sync, R.drawable.cmcc_setting_conversion_down);
                views.setImageViewResource(R.id.ind_sync, R.drawable.appwidget_settings_ind_on_c);
                break;
            case STATE_INTERMEDIATE:
              views.setImageViewResource(R.id.img_sync, R.drawable.cmcc_setting_conversion_nor);
              views.setImageViewResource(R.id.ind_sync, R.drawable.appwidget_settings_ind_on_c);
            break;
        }

//        if (getSync(context)) {
//            views.setImageViewResource(R.id.img_sync, R.drawable.cmcc_setting_conversion_down);
//            views.setImageViewResource(R.id.ind_sync, R.drawable.appwidget_settings_ind_on_c);
//        } else {
//            views.setImageViewResource(R.id.img_sync, R.drawable.cmcc_setting_conversion_nor);
//            views.setImageViewResource(R.id.ind_sync, R.drawable.appwidget_settings_ind_off_c);
//        }
        if (getGpsState(context)) {
            views.setImageViewResource(R.id.img_gps, R.drawable.cmcc_setting_signal_down);
            views.setImageViewResource(R.id.ind_gps, R.drawable.appwidget_settings_ind_on_c);
        } else {
            views.setImageViewResource(R.id.img_gps, R.drawable.cmcc_setting_signal_nor);
            views.setImageViewResource(R.id.ind_gps, R.drawable.appwidget_settings_ind_off_c);
        }

        switch (sBluetoothState.getTriState(context)) {
            case STATE_DISABLED:
                logger.d("Updating bluetooth button,state =  "+ STATE_DISABLED);
                views.setImageViewResource(R.id.img_bluetooth, R.drawable.cmcc_setting_bluetooth_nor);
                views.setImageViewResource(R.id.ind_bluetooth, R.drawable.appwidget_settings_ind_off_c);
                break;
            case STATE_ENABLED:
                logger.d("Updating bluetooth button,state =  "+ STATE_ENABLED);
                //views.setImageViewResource(R.id.img_bluetooth, R.drawable.cmcc_setting_bluetooth_down);
                views.setImageViewResource(R.id.ind_bluetooth, R.drawable.appwidget_settings_ind_on_c);
                break;
            case STATE_INTERMEDIATE:
                // In the transitional state, the bottom green bar
                // shows the tri-state (on, off, transitioning), but
                // the top dark-gray-or-bright-white logo shows the
                // user's intent.  This is much easier to see in
                // sunlight.
                if (sBluetoothState.isTurningOn()) {
                    views.setImageViewResource(R.id.img_bluetooth, R.drawable.cmcc_setting_bluetooth_nor);
                    views.setImageViewResource(R.id.ind_bluetooth, R.drawable.appwidget_settings_ind_mid_c);
                } else {
                    views.setImageViewResource(R.id.img_bluetooth, R.drawable.cmcc_setting_bluetooth_nor);
                    views.setImageViewResource(R.id.ind_bluetooth, R.drawable.appwidget_settings_ind_mid_c);
                }
                break;
        }
    }

    /**
     * Gets the state of DataconnectionOnBoot.
     *
     * @param context
     *
     */
    private static int getDataOnBootState(Context context){
        ConnectivityManager mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        try {
            //tempState= mConnMgr.getMobileDataEnabled();
        } catch (Exception e) {
            logger.d("getDataOnBootState Exception");
            return STATE_INTERMEDIATE;
        }

        if (dataswitching){
            logger.d("getDataOnBootState dataswitching");
            return STATE_INTERMEDIATE;
        }

        if (tempState == false){
            logger.d("DATA_DISCONNECTED");
            return STATE_DISABLED;
        } else if (tempState == true ){
            logger.d("DATA_CONNECTED");
            return STATE_ENABLED;
        } else {
            logger.d("DATA_else");
            return STATE_INTERMEDIATE;
        }
    }

    /**
     * Toggles the state of DataconnectionOnBoot.
     *
     * @param context
     */

    private void toggleDataOnBoot(Context context){
        ConnectivityManager mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (getDataOnBootState(context) == STATE_DISABLED){
            //mConnMgr.setMobileDataEnabled(true);
        } else if (getDataOnBootState(context) == STATE_ENABLED){
            //mConnMgr.setMobileDataEnabled(false);
            dataswitching = true;
            logger.d("set dataswitching = true");
            handler.sendMessageDelayed(handler.obtainMessage(POWEROFF_DATAONBOOT), 4000);
        }
    }
    /**
     * Gets the state of GPS location.
     *
     * @param context
     * @return true if enabled.
     */
    private static boolean getGpsState(Context context) {
        ContentResolver resolver = context.getContentResolver();
        return Settings.Secure.isLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER);
    }

    /**
     * Toggles the state of GPS.
     *
     * @param context
     */
    private void toggleGps(Context context) {
        ContentResolver resolver = context.getContentResolver();
        boolean enabled = getGpsState(context);
        Settings.Secure.setLocationProviderEnabled(resolver, LocationManager.GPS_PROVIDER,
                !enabled);
    }

    Handler handler = new Handler(){

        public void handleMessage(Message msg) {
            switch (msg.what) {
            case POWEROFF_DATAONBOOT:
                logger.d("set dataswitching = false");
                dataswitching = false;
                break;
            }
            super.handleMessage(msg);
        }

    };
}
